x86: don't disable MSI in order to mask an IRQ
authorKeir Fraser <keir.fraser@citrix.com>
Thu, 13 Nov 2008 16:31:08 +0000 (16:31 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Thu, 13 Nov 2008 16:31:08 +0000 (16:31 +0000)
... as that's not really correct, and there are devices which can't
even cope with that. Instead, check whether an MSI IRQ can be masked,
and if it can't, treat it just like a level triggered IO-APIC IRQ.

There's one other bug fix in here, correcting an off-by-one error on
the entry_nr range check in __pci_enable_msix().

Signed-off-by: Jan Beulich <jbeulich@novell.com>
xen/arch/x86/irq.c
xen/arch/x86/msi.c
xen/include/asm-x86/msi.h

index efb73ad011c4130250a388d1a62263567ccac7f1..a4fed17004066ae33005a2ecf82c1b454a30fe31 100644 (file)
@@ -463,13 +463,18 @@ int pirq_acktype(struct domain *d, int irq)
     /*
      * Edge-triggered IO-APIC and LAPIC interrupts need no final
      * acknowledgement: we ACK early during interrupt processing.
-     * MSIs are treated as edge-triggered interrupts.
      */
     if ( !strcmp(desc->handler->typename, "IO-APIC-edge") ||
-         !strcmp(desc->handler->typename, "local-APIC-edge") ||
-         !strcmp(desc->handler->typename, "PCI-MSI") )
+         !strcmp(desc->handler->typename, "local-APIC-edge") )
         return ACKTYPE_NONE;
 
+    /*
+     * MSIs are treated as edge-triggered interrupts, except
+     * when there is no proper way to mask them.
+     */
+    if ( desc->handler == &pci_msi_type )
+        return msi_maskable_irq(desc->msi_desc) ? ACKTYPE_NONE : ACKTYPE_EOI;
+
     /*
      * Level-triggered IO-APIC interrupts need to be acknowledged on the CPU
      * on which they were received. This is because we tickle the LAPIC to EOI.
index 8bf5b4a8e3c0a42537f0cb75cde88d096c2f17d7..b5fd6a1f8b92c8a6e035ca9d4239ac18f437a832 100644 (file)
@@ -298,6 +298,13 @@ static void msix_flush_writes(unsigned int irq)
     }
 }
 
+int msi_maskable_irq(const struct msi_desc *entry)
+{
+    BUG_ON(!entry);
+    return entry->msi_attrib.type != PCI_CAP_ID_MSI
+           || entry->msi_attrib.maskbit;
+}
+
 static void msi_set_mask_bit(unsigned int irq, int flag)
 {
     struct msi_desc *entry = irq_desc[irq].msi_desc;
@@ -318,8 +325,6 @@ static void msi_set_mask_bit(unsigned int irq, int flag)
             mask_bits &= ~(1);
             mask_bits |= flag;
             pci_conf_write32(bus, slot, func, pos, mask_bits);
-        } else {
-            msi_set_enable(entry->dev, !flag);
         }
         break;
     case PCI_CAP_ID_MSIX:
@@ -649,7 +654,7 @@ static int __pci_enable_msix(struct msi_info *msi)
     pos = pci_find_cap_offset(msi->bus, slot, func, PCI_CAP_ID_MSIX);
     control = pci_conf_read16(msi->bus, slot, func, msi_control_reg(pos));
     nr_entries = multi_msix_capable(control);
-    if (msi->entry_nr > nr_entries)
+    if (msi->entry_nr >= nr_entries)
     {
         spin_unlock(&pdev->lock);
         return -EINVAL;
index c72f9d69c5aa6243f74226fc690e214edb5c1e32..f1462d2dc81dffce30fdf0fd0db4236cb7923c3b 100644 (file)
@@ -97,6 +97,8 @@ struct msi_desc {
        int remap_index;                /* index in interrupt remapping table */
 };
 
+int msi_maskable_irq(const struct msi_desc *);
+
 /*
  * Assume the maximum number of hot plug slots supported by the system is about
  * ten. The worstcase is that each of these slots is hot-added with a device,